﻿using System;
using System.Text.RegularExpressions;
using BDSA12;

namespace Week_37_Part_1 {

    /// <summary>
    /// Class for searching a string using regular expressions
    /// </summary>
    class SearchTool {

        /// <summary>
        /// Fields
        /// </summary>
        private string content = "";
        private string userInput = "";

        /// <summary>
        /// Main method constructs the tool.
        /// </summary>
        /// <param name="args">the input (it is not used)</param>
        static void Main(string[] args) {
            SearchTool p = new SearchTool();
            p.readInput();
        }

        /// <summary>
        /// The switch loop that calls ShowText on the desired search method
        /// </summary>
        public SearchTool(String file = "../../testFile.txt") {
            content = TextFileReader.ReadFile(file);
        }

        /// <summary>
        /// Reads the input from the user.
        /// </summary>
        public void readInput() {
            while (true) {
                Console.Write("\nEnter search query: ");
                userInput = Console.ReadLine();
                if (userInput.Length == 0) {
                    break;
                }
                // string + string
                else if (userInput.Contains("+")) {
                    String[] words = userInput.Split('+');
                    ShowText(SearchTwoWords(words[0].Trim(), words[1].Trim()));
                }
                // string*
                //TODO: fix that it fails on input: '(*' but not on ' (*' - maybe string is too short?
                else if (userInput.EndsWith("*")) {
                    ShowText(SearchStarting(userInput.Substring(0, userInput.Length - 1)));
                }
                // *string
                else if (userInput.StartsWith("*")) {
                    ShowText(SearchEnding(userInput.Substring(1, userInput.Length - 1)));
                }
                // normal search
                else {
                    ShowText(Search(userInput));
                }
            }
        }

        /// <summary>
        /// The method that prints to console
        /// </summary>
        /// <param name="match">The collection of matches</param>
        public void ShowText(MatchCollection match) {

            int i = 0, h = 0, j = 0; //indices for array traversal

            MatchCollection urls = SearchURLs();
            MatchCollection dates = SearchDates();

            try {
                for (int n = 0; n < content.Length; n++) {
                    //if between start of word, and through to length of word
                    //in search string
                    if (n >= match[i].Index && n < match[i].Index + match[i].Length) {
                        Console.BackgroundColor = ConsoleColor.Yellow;
                        Console.ForegroundColor = ConsoleColor.Black;
                        Console.Write(content[n]);

                    }
                    //URLS
                    else if (n >= urls[h].Index && n < urls[h].Index + urls[h].Length) {
                        Console.BackgroundColor = ConsoleColor.Black;
                        Console.ForegroundColor = ConsoleColor.Blue;
                        Console.Write(content[n]);

                    }
                    //DATES
                    else if (n >= dates[j].Index && n < dates[j].Index + dates[j].Length) {
                        Console.BackgroundColor = ConsoleColor.Black;
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write(content[n]);

                    }
                    //Anything else
                    else {
                        Console.BackgroundColor = ConsoleColor.Black;
                        Console.ForegroundColor = ConsoleColor.White;
                        Console.Write(content[n]);
                    }
                    //increment counter
                    if (n == match[i].Index + match[i].Length && i < match.Count - 1)
                        i++;
                    if (n == urls[h].Index + urls[h].Length && h < urls.Count - 1)
                        h++;
                    if (n == dates[j].Index + dates[j].Length && j < dates.Count - 1)
                        j++;
                }
            }
            catch (ArgumentOutOfRangeException e) {
                Console.Error.WriteLine("Substring '" + Regex.Unescape(userInput) + "' not found!");
            }
        }


        /// <summary>
        /// Locates the URLs in the content-string
        /// </summary>
        /// <returns>A collection of matches of URLs</returns>
        internal MatchCollection SearchURLs() {
            string regex = @"http(s)?://\S*";
            MatchCollection matches = Regex.Matches(content, regex);
            return matches;
        }

        /// <summary>
        /// Locates the Dates in the content-string
        /// </summary>
        /// <returns>A collection of matches of Dates</returns>
        internal MatchCollection SearchDates() {
            string regex = @"\b(0[1-9]|[1-2][0-9]|3[01])\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s([1-2][0-9]{3})\b";
            MatchCollection matches = Regex.Matches(content, regex);
            return matches;
        }

        /// <summary>
        /// Normal search function
        /// Given a keyword print the text file on the console highlighting the matches with a yellow background (you can assume only one keyword)
        /// </summary>
        /// <param name="keyword">Search string</param>
        /// <returns>A collection of matches</returns>
        internal MatchCollection Search(string keyword) {
            keyword = Regex.Escape(keyword);
            //Skal det kun være hele ord ?
            // og ikke fx. e i et ord?
            MatchCollection matches = Regex.Matches(content, @"\b" + keyword + @"\b");
            return matches;
        }

        /// <summary>
        /// String + String
        /// Means that two adjacent keywords should be present one after the other, e.g. text + file matches “text file” but does not match “text big file”
        /// </summary>
        /// <param name="firstKeyword">#1 search string</param>
        /// <param name="secondKeyword">#2 search string</param>
        /// <returns>A collection of matches</returns>
        internal MatchCollection SearchTwoWords(string firstKeyword, string secondKeyword) {
            firstKeyword = Regex.Escape(firstKeyword);
            secondKeyword = Regex.Escape(secondKeyword);
            MatchCollection matches = Regex.Matches(content, @"\b" + firstKeyword + @"\s" + secondKeyword + @"\b");
            return matches;
        }

        /// <summary>
        /// String*
        /// After a keyword means search for words starting with keyword e.g. inter* matches “internet”
        /// </summary>
        /// <param name="keyword">Search string</param>
        /// <returns>A collection of matches</returns>
        internal MatchCollection SearchStarting(string keyword) {
            keyword = Regex.Escape(keyword);
            MatchCollection matches = Regex.Matches(content, @"\b" + keyword + @"\S*");
            return matches;
        }

        /// <summary>
        /// *String
        /// Before a keyword means search for words ending with keyword e.g. *net matches “internet” and “intranet”
        /// </summary>
        /// <param name="keyword">Search string</param>
        /// <returns>A collection of matches</returns>
        internal MatchCollection SearchEnding(string keyword) {
            keyword = Regex.Escape(keyword);
            MatchCollection matches = Regex.Matches(content, @"\S*" + keyword + @"\b");
            return matches;
        }

    }

}